package org.fenixsoft.jvm.chapter9.my;


import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.*;

import java.lang.reflect.Method;

public class CglibDynamicProxyTest {

    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:/proxy");
        proxyComment();
    }

    static void proxyComment(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CommentServiceImpl.class);

        Callback[] callbacks = new Callback[]{
                new CommentMethodInterceptor(),
                //NoOp.INSTANCE, //生成的Class没有覆盖原始类的任何方法，被调用时，直接调用原始类的方法
                //new CommentLazyLoader(),
                //new CommentDispatcher(),
                //new CommentInvocationHandler(),
               // new CommentFixedValue(),
        };

        enhancer.setCallbacks(callbacks);

        final CommentService proxyService = (CommentService) enhancer.create();
        System.out.println("create proxyService");

        proxyService.comment();

        //第二次调用
        //proxyService.comment();
    }


    static class CommentMethodInterceptor implements MethodInterceptor{
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("add 1 score");
            return result;
        }
    }

    /**
     * 类似于spring scope的singleton，
     *
     * enhancer.create()创建了动态生成的class对象实例proxyService,
     * proxyService在第一次调用comment()的中调用LazyLoader.loadObject()进行初始化，
     * 并且将返回的Object作为proxyService实例变量存储起来，之后每次调动都会判断该实例是否为null，
     * 如果不为null，则直接返回object，并不会调用loadObject方法()。
     *
     * LazyLoader可以在被代理对象实例化的时候，对被代理对象进行功能增强，以后每次都返回被增强的对象。
     */
    static class CommentLazyLoader implements LazyLoader {
        @Override
        public Object loadObject() throws Exception {
            System.out.println("lazy loader, 第一次调用被代理实现类方法时，增强功能");
            return new CommentServiceImpl();
        }
    }

    /**
     * 类似于spring scope的prototype
     *
     * Dispatcher与LazyLoader类似，但是proxyService每次调用方法时，都会调用loadObject
     */
    static class CommentDispatcher implements Dispatcher {
        @Override
        public Object loadObject() throws Exception {
            System.out.println("dispatcher,每次调用被代理实现类方法时，增强功能");
            return new CommentServiceImpl();
        }
    }

    static class CommentInvocationHandler implements InvocationHandler{

        /*****
         * invocationHandler的invoke方法传入的method和proxy都是代理本身对象, 与menthodInterceptor的method是被代理对象区分开
         * 切忌重复调用，会循环调用
         * @param proxy 代理类本身
         * @param method 代理类内部的方法
         * @param args  参数
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("invoke  handler");
            Object result = method.invoke(proxy.getClass().getSuperclass().newInstance(), args);
            return result;
        }
    }

    /**
     * 该callback相当于重写了相应的函数实现。并不会调用原函数
     */
    static class CommentFixedValue implements FixedValue {
        @Override
        public Object loadObject() throws Exception {
            System.out.println("不会调用被代理对象的任何方法");
            return true;
        }
    }

}
